/**
 * 
 */
package com.cqcis.uip.base.framework.utils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.osgi.context.BundleContextAware;

import com.cqcis.uip.base.framework.FrameworkConstants;
import com.cqcis.uip.base.framework.core.config.PropertiesLocationUtil;
import com.cqcis.uip.base.framework.core.config.PropertiesRepositoryService;
import com.cqcis.uip.base.framework.service.EncryptorService;

/**
 * 属性配置修改类, 扩展Spring
 * 
 * @author huangmy
 * @date 2008-2-16
 * @author liuhz
 * @date 2008-9-22 属性文件编解码支持
 * 
 *       <pre>
 * 在对需要解码的属性值进行编码后配置，如下
 * datasource.password=ENC(i0IAcx54Ya4w91Mm1AMOnw==)
 * </pre>
 */
public class PropertyPlaceholderConfigurerAdaptor extends PropertyPlaceholderConfigurer implements BundleContextAware,
		InitializingBean {
	private BundleContext context; /* 该bundle上下文 */
	private Resource[] locations; // 配置文件路径
	private ConfigurableListableBeanFactory beanFactory; // Spring配置工厂
	private EncryptorService encryptor;

	public void afterPropertiesSet() throws Exception {
		// do nothing
	}

	@Override
	public void setLocation(Resource location) {
		setLocations(new Resource[] { location });
	}

	/**
	 * 重写location设置
	 */
	@Override
	public void setLocations(Resource[] locations) {
		if (locations == null) {
			throw new NullPointerException("the config locations files can't be null.");
		}

		this.locations = locations; // 保存资源

		if (this.context != null) { // 上下文存在，则定制路径
			this.locations = createCustomizerLocations(locations, this.context);
			super.setLocations(this.locations);
			callSrpingPostProcessBeanFactoryIfNoDeal(); // 配置
		}
	}

	/**
	 * 获取OSGI上下文
	 */
	public void setBundleContext(BundleContext context) {
		this.context = context; // 保存OSGI上下文

		ServiceReference sr = this.context.getServiceReference(EncryptorService.class.getName());
		if (sr != null) {
			this.encryptor = (EncryptorService) this.context.getService(sr);
		}

		if (this.locations != null) { // 原始资源存在，则定制路径
			this.locations = createCustomizerLocations(this.locations, this.context);
			super.setLocations(this.locations);
			callSrpingPostProcessBeanFactoryIfNoDeal(); // 配置
		}
	}

	/**
	 * 调用SPRING工厂，如果没有调用
	 */
	private void callSrpingPostProcessBeanFactoryIfNoDeal() {
		if (this.beanFactory != null) {
			postProcessBeanFactory(this.beanFactory);
		}
	}

	/**
	 * 覆写配置文件处理
	 */
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		if (this.locations == null || this.context == null) {
			this.beanFactory = beanFactory; // 未处理, 保存Spring配置工厂
			return;
		}

		super.postProcessBeanFactory(beanFactory);
	}

	/**
	 * 通过上下文配置定制资源
	 * 
	 * @param locations
	 * @param context
	 * @return
	 */
	private Resource[] createCustomizerLocations(Resource[] locations, BundleContext context) {
		// 查看配置库中是否有配置文件，如果有，则使用
		ServiceReference rf = context.getServiceReference(PropertiesRepositoryService.class.getName());

		Map<String, String> propertiesLocations = new HashMap<String, String>();
		PropertiesRepositoryService repository = null;
		if (rf != null) {
			repository = (PropertiesRepositoryService) context.getService(rf);
		}

		String bundleLocation = context.getBundle().getLocation();

		if (repository != null) {
			List<String> pls = repository.getPropertiesLocations(bundleLocation);
			if (pls != null) {
				for (String p : pls) {
					propertiesLocations.put(p, "T");
				}
			}
		}

		// 查看是否有相应的配置文件存在，有，则使用
		for (Resource r : locations) {
			String maybeLocation = PropertiesLocationUtil.createPropertiesLocationFor(bundleLocation, r.getFilename());
			File propFile = new File(maybeLocation);
			if (propFile.exists()) {
				String t = propertiesLocations.get(maybeLocation);
				if (t == null) {
					propertiesLocations.put(maybeLocation, "T");
				}
			}
		}

		List<Resource> resources = new ArrayList<Resource>();
		for (String propertiesLocation : propertiesLocations.keySet()) {
			resources.add(new FileSystemResource(propertiesLocation));
		}

		if (resources.size() > 0) {
			locations = resources.toArray(new Resource[resources.size()]);
		}

		return locations;
	}

	@Override
	protected String convertPropertyValue(String originalValue) {
		return this.encryptor.isEncryptedValue(originalValue) ? this.encryptor.decrypt(originalValue) : originalValue;
	}
	
	@Override
	protected void loadProperties(Properties props) throws IOException {
		super.loadProperties(props);
		
		for (String[] prop : FrameworkConstants.DEFAULT_FILE_PROPS_KEY_VALUE) {
			String key = prop[0];
			String value = prop[1];
			
			if (!props.containsKey(key)) {
				props.put(key, value);
			}			
		}
	}
}
